package org.mihalovic.PES.GUI;

import java.util.ArrayList;
import java.util.Iterator;

import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

import org.mihalovic.PES.data.DataManager;
import org.mihalovic.PES.data.Domain;



/**
 * @author Martin Mihalovic
 */
public class SourceDataSelectionPanel extends JPanel implements SourceDataChangedListener, TableModelListener {
    private final JLabel noDataMessage;
    private JTextArea queryArea;
    private JTable table;
    private ArrayList<TableRowElement> checkList;

    private boolean dataAreLatest;



    public SourceDataSelectionPanel() {
        super();

        dataAreLatest = true;

        noDataMessage = new JLabel("Loading data, please wait...", JLabel.CENTER);
        noDataMessage.setForeground(Color.RED);
        this.setLayout(new BorderLayout());
        reset();
    }


    /**
     * Indicates whether domain selection has changed
     * from last call of <code>GetSelectedDomains()</code>
     * @return false = selection changed
     */
    public boolean DataAreLatest() {
        return dataAreLatest;
    }



    public void SourceDataChanged() {
        DataManager reader = AppWindow.getInstance().GetSourceGraphReader();
        ArrayList<Domain> data = reader.GetDomainsWithRatingCounts();
        setData(data);
    }


    private void setData(ArrayList<Domain> data) {
        checkList = new ArrayList<TableRowElement>();

        int bound = data.size();
        for(int i=0; i<bound; i++)
        {
            Domain dom = data.get(i);
            TableRowElement tre = new TableRowElement(/*dom.ID(),*/ dom.Name(), dom.RatingsCount());
            tre.addChangeListener(new ChangeListener(){
                public void stateChanged(ChangeEvent e) {
                    dataAreLatest=false;
                }
            });
            checkList.add( tre );
        }

        initializeGui();        
        
        this.setSize(this.getWidth(), this.getHeight()-1);         //Trick to do efficient repaint
    }


    private void initializeGui() {
        this.removeAll();

        SimpleTableModel model = new SimpleTableModel(checkList);
        model.addTableModelListener(this);
        table = new JTable(model);

        table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        table.setRowSelectionAllowed(true);
        table.setColumnSelectionAllowed(false);
        table.setAutoCreateRowSorter(true);                     //allow column sorting
        table.getColumnModel().getColumn(1).setMaxWidth(150);
        table.getColumnModel().getColumn(1).setMinWidth(150);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(2).setMaxWidth(100);
        table.getColumnModel().getColumn(2).setMinWidth(100);
        table.getColumnModel().getColumn(2).setPreferredWidth(100);

        table.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent ke) {
                if (ke.getKeyCode() == KeyEvent.VK_SPACE) { adjustRowsCheckStatus(); }
            }
        });

        JPanel upperPanel = new JPanel();
        upperPanel.setBackground(Color.ORANGE);
        upperPanel.setLayout(new BoxLayout(upperPanel, BoxLayout.Y_AXIS));
        upperPanel.setMinimumSize(new Dimension(500, 210));
        upperPanel.setPreferredSize(new Dimension(500, 210));
        try{
            ImagePanel logoPanel = new ImagePanel("./img/PES_logo.png");
            logoPanel.setPreferredSize(new Dimension(600, 100));
            JPanel lpHolder = new JPanel();
            lpHolder.setBackground(Color.WHITE);
            lpHolder.add(logoPanel);
            upperPanel.add(lpHolder, BorderLayout.PAGE_START);
        } catch(IOException ioe) {
            System.err.println("Unable to load logo ./img/PES_logo.png \n\n" + ioe.getMessage());
        }
        
        JPanel queryPanel = new JPanel();
        queryPanel.setBackground(Color.WHITE);
        JLabel queryLabel = new JLabel("<html><h3>Query:</h3>(use table below<br/>to build a query)</html>");
        queryLabel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        queryLabel.setBorder(new EmptyBorder(0, 6, 0, 6));
        queryPanel.add(queryLabel, BorderLayout.LINE_START);
        queryArea = new JTextArea();
        queryArea.setFont(new Font("Courier new", Font.PLAIN, 12));
        queryArea.setLineWrap(true);
        queryArea.setWrapStyleWord(true);
        queryArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(queryArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setPreferredSize(new Dimension(500, 100));
        scrollPane.setMinimumSize(new Dimension(500, 100));
        scrollPane.setMaximumSize(new Dimension(500, 100));
        queryPanel.add(scrollPane, BorderLayout.CENTER);
        
        upperPanel.add(queryPanel);

        JScrollPane sp = new JScrollPane(table);
        table.setFillsViewportHeight(true);

        JPanel lowerRightPanel = new JPanel();
        lowerRightPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        lowerRightPanel.setMinimumSize(new Dimension(30, 30));
        lowerRightPanel.setMaximumSize(new Dimension(10240, 30));


        JCheckBox selCB = new JCheckBox("Select All");
        selCB.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                setAllRowsChecked( e.getStateChange() == ItemEvent.SELECTED );
            }
        });
        lowerRightPanel.add(selCB);

        JPanel lowerPanel = new JPanel();
        lowerPanel.setLayout(new BorderLayout());
        lowerPanel.setMaximumSize(new Dimension(10240, 30));
        lowerPanel.add(lowerRightPanel, BorderLayout.EAST);

        JPanel verticallySplitPanel = new JPanel();
        verticallySplitPanel.setLayout(new BorderLayout());
                
        verticallySplitPanel.add(upperPanel, BorderLayout.PAGE_START);
        verticallySplitPanel.add(sp, BorderLayout.CENTER);
        verticallySplitPanel.add(lowerPanel, BorderLayout.PAGE_END);
        
        add(verticallySplitPanel);
    }


    private void adjustRowsCheckStatus() {
        boolean toSelect = !areAllSelectedRowsChecked();

        int[] selectedRowsIndices = table.getSelectedRows();

        for(int i=0; i<selectedRowsIndices.length; i++)
            table.setValueAt(toSelect, selectedRowsIndices[i], 2);
    }


    private boolean areAllSelectedRowsChecked() {
        int[] selectedRowsIndices = table.getSelectedRows();

        for(int i=0; i<selectedRowsIndices.length; i++)
            if( !(Boolean)table.getValueAt(selectedRowsIndices[i], 2) ) return false;

        return true;
    }


    private void setAllRowsChecked(boolean checked) {
        int rows = table.getRowCount();

        for(int i=0; i<rows; i++)
            table.setValueAt(checked, i, 2);
    }


    /**
     * @return Array of domain names selected by user.
     */
/*del    public String[] GetSelectedDomainIDs() {                    //TODO: this will become obsolete. This control can't know about domain IDs
        dataAreLatest = true;
        ArrayList<String> result = new ArrayList<String>();

        Iterator iter = checkList.iterator();
        while(iter.hasNext())
        {
            TableRowElement le = (TableRowElement)iter.next();
            if(le.isSelected())
                result.add(le.DomainID());
        }

        return result.toArray(new String[result.size()]);
    }
*/    



    /**
     * Clears data source and sets warning message to this panel
     */
    private void reset() {
        this.removeAll();
        checkList = null;
        table = null;
        this.add(noDataMessage,  BorderLayout.CENTER);
    }

    public void tableChanged(TableModelEvent e) {
        String query = "";
        
        Iterator iter = checkList.iterator();
        while(iter.hasNext())
        {
            TableRowElement le = (TableRowElement)iter.next();
            if(le.isSelected())
                query += "\"" + le.DomainName() + "\" OR ";
        }
        if(query.endsWith(" OR "))
            query = query.substring(0, query.length() - 4);

        queryArea.setText(query);
        AppWindow.getInstance().GetQueryHolder().setUserQuery(query);
    }
}



class SimpleTableModel extends AbstractTableModel {

    private String[] columnHeaders = new String[] {"Domain", "Ratings in Domain", "Use in ranking"};
    private ArrayList<TableRowElement> data;


    /**
     * @param data Vector of data used to fill rows
     */
    public SimpleTableModel(ArrayList<TableRowElement> data) {
        this.data = data;
    }

    public int getRowCount() { return data.size(); }
    public int getColumnCount() { return columnHeaders.length; }
    @Override
    public String getColumnName(int col) { return columnHeaders[col]; }

    public Object getValueAt(int rowIndex, int columnIndex) {
        if(columnIndex==0)
            return data.get(rowIndex).DomainName();
        else if(columnIndex==1)
            return data.get(rowIndex).RatingsInDomain();
        else if(columnIndex==2)
            return data.get(rowIndex).isSelected();
        else
            throw new ArrayIndexOutOfBoundsException("Invalid colum index: "+columnIndex);
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        data.get(row).setSelected( (Boolean)value );
        this.fireTableCellUpdated(row, col);
    }

    @Override
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return (row<=getRowCount() && col==2);
    }
}
